﻿#ifndef K_DEF_H
#define K_DEF_H
#pragma once

#include "K_Winsock.h"
#include "KList.h"
#include "KNamespace.h"

class KKey;
class KMultiplexor;
class KSocket;

K_NAMESPACE_BEG(KDef)

class AcceptRequest;
class BasicRequest;
class ConnectRequest;
class DisconnRequest;
class IoRequest;
class MessageRequest;
class NullRequest;
class TransmitRequest;

typedef void *Life;

enum DefaultParam {
    DefaultAcceptSize   = sizeof(SOCKADDR_STORAGE) * 2 + 32,
    DefaultChunkSize    = 4096,
    DefaultExpireCount  = 3,
    DefaultInterval     = 2000,
    DefaultPoolSize     = 256,
    DefaultTimeOut      = 5000
};

enum SockError {            //   Acceptor     Client  Connector  Messenger
    NoError = 0,            // ---------- ---------- ---------- ----------
    ErrorAcceptorInit,      //          √
    ErrorAddToIocp,         //          √          √          √          √
    ErrorCallAccept,        //          √
    ErrorCallConnect,       //                                √
    ErrorCallDisconnect,    //                     √          √
    ErrorCallRecv,          //                     √          √          √
    ErrorCallSend,          //                     √          √          √
    ErrorCallTransmit,      //                     √          √
    ErrorClientInit,        //          √
    ErrorConnectorInit,     //                                √
    ErrorDisconnRecv,       //                     √          √          √
    ErrorDisconnSend,       //                     √          √          √
    ErrorFailedAccept,      //          √
    ErrorFailedConnect,     //                                √
    ErrorFailedDisconnect,  //                     √          √
    ErrorFailedReceive,     //                     √          √          √
    ErrorFailedSend,        //                     √          √          √
    ErrorFailedTransmit,    //                     √          √
    ErrorGetStatus,         //
    ErrorMessengerInit,     //                                           √
    ErrorNotStarted,        //
    ErrorPostStatus,        //          √          √          √          √
    ErrorTransmitInit,      //                     √          √
    ErrorUpdateContext,     //                     √          √
    ErrorWaitTimeOut        //
};

class SocketContext : public KList::Node {
public:
    SocketContext() : m_idle(0) {}
public:
    void addRequest(NullRequest *request);
    virtual KSocket *getSocket()    { return NULL; }
    bool hasPendingRequest() const  { return !m_request.isEmpty(); }
    LONG increaseIdleCount()        { return InterlockedIncrement(&m_idle); }
    bool isIdle() const             { return m_idle > 0; }
    void removeRequest(NullRequest *request);
    void resetIdleCount()           { InterlockedExchange(&m_idle, 0); }
protected:
    void clearRequests();
private:
    KList           m_request;
    volatile LONG   m_idle;
};

class RequestInfo : KNoCopy {
public:
    explicit RequestInfo(KMultiplexor *host)
        : more(false), m_host(KVerify(host)) {}
public:
    void failure(AcceptRequest *request);
    void failure(ConnectRequest *request);
    void failure(DisconnRequest *request);
    void failure(IoRequest *request);
    void failure(TransmitRequest *request);
    void success(AcceptRequest *request);
    void success(ConnectRequest *request);
    void success(DisconnRequest *request);
    void success(IoRequest *request);
    void success(MessageRequest *request);
    void success(TransmitRequest *request);
public:
    bool            more;
    DWORD           bytes;
    DWORD           error;
    SocketContext * node;
private:
    KMultiplexor *  m_host;
};

class NullRequest : public KList::Node {};

class BasicRequest : public NullRequest, public WSAOVERLAPPED {
public:
    BasicRequest()                      { reset(); }
public:
    void onFailure(RequestInfo &info)   { onFailureImp(info); }
    void onSuccess(RequestInfo &info)   { onSuccessImp(info); }
    void reset()
    {
        WSAOVERLAPPED::hEvent       = NULL;
        WSAOVERLAPPED::Internal     = 0;
        WSAOVERLAPPED::InternalHigh = 0;
        WSAOVERLAPPED::Offset       = 0;
        WSAOVERLAPPED::OffsetHigh   = 0;
        WSAOVERLAPPED::Pointer      = NULL;
    }
protected:
    virtual void onFailureImp(RequestInfo &info);
    virtual void onSuccessImp(RequestInfo &info);
};

class AcceptRequest : public BasicRequest {
public:
    AcceptRequest() : client(NULL) {}
    virtual ~AcceptRequest();
protected:
    virtual void onFailureImp(RequestInfo &info);
    virtual void onSuccessImp(RequestInfo &info);
public:
    char        buf[KDef::DefaultAcceptSize];
    KSocket *   client;
};

class ConnectRequest : public BasicRequest {
protected:
    virtual void onFailureImp(RequestInfo &info);
    virtual void onSuccessImp(RequestInfo &info);
};

class DisconnRequest : public BasicRequest {
protected:
    virtual void onFailureImp(RequestInfo &info);
    virtual void onSuccessImp(RequestInfo &info);
};

class IoRequest : public BasicRequest {
public:
    explicit IoRequest(size_t bufSize) : key(NULL)
    {
        buffer.buf = NULL;
        buffer.len = 0;
        resize(bufSize);
    }
    virtual ~IoRequest();
public:
    static void free(void *data);
    void resize(size_t bufSize, bool expand = true);
protected:
    virtual void onFailureImp(RequestInfo &info);
    virtual void onSuccessImp(RequestInfo &info);
public:
    bool        isRecv;
    KKey *      key;
    size_t      bytesSent;
    size_t      bytesTotal;
    SOCKADDR_IN addrTo; // For KUdpSocket::asyncSend()
    WSABUF      buffer;
};

class MessageRequest : public BasicRequest {
public:
    explicit MessageRequest(KKey *userKey = NULL) : key(userKey) {}
    virtual ~MessageRequest();
protected:
    virtual void onFailureImp(RequestInfo &info);
    virtual void onSuccessImp(RequestInfo &info);
public:
    KKey *key;
};

class TransmitRequest : public BasicRequest {
public:
    explicit TransmitRequest(HANDLE hFile, KKey *userKey = NULL) : file(hFile), key(userKey) {}
    virtual ~TransmitRequest();
protected:
    virtual void onFailureImp(RequestInfo &info);
    virtual void onSuccessImp(RequestInfo &info);
public:
    HANDLE  file;
    KKey *  key;
};

inline void SocketContext::addRequest(NullRequest *request)
{
    m_request.pushFront(request);
}

inline void SocketContext::removeRequest(NullRequest *request)
{
    m_request.cutOff(request);
}

inline void SocketContext::clearRequests()
{
    m_request.destroy();
}

K_NAMESPACE_END(KDef)

#endif // K_DEF_H